/* econ.c
 *
 * This file contains all the fuctions for econ
 *
 */

/*-----------------------------------------------------------------
 * Econ	functions
 *
 */

#include "copyrite.h"
#include "config.h"
#include <string.h>
#include <strings.h>
#include <math.h>
#include <stdio.h>
#include "conf.h"
#include "externs.h"
#include "parse.h"
#include "confmagic.h"
#include "function.h"
#include "intrface.h"
#include "ansi.h"
#include "match.h"
#include "space.h"
#include "flags.h"
#include "dbdefs.h"
#include "mushdb.h"
#include "lock.h"
#include "dbdefs.h"
#include "attrib.h"
#include "log.h"
#include "econ.h"

int split_building(char *instr, char *zone, char *building) {
	char tmp[20];
	char *tp = tmp;
	//dbref z;
	

	strcpy(tmp, instr);
	strcpy(zone, strsep(&tp, "_"));	
	strcpy(building, tp);

	return 1;
}

int bext(dbref data, char *instr, int pos, char *outstr) {
	ATTR *a;
	char sep;
	int start, len;
	char *s, *r;

	a = atr_get(data, instr);
	if (!a) return 0;
	
	s = (char *) alloca (BUFFER_LEN + 1);
	strcpy(s, atr_value(a));	
  	start = pos;
  	len = 1;
  	sep = '|';

  	if ((start < 1) || (len < 1))
    		return 0;

  	/* Go to the start of the token we're interested in. */
  	start--;
  	s = trim_space_sep(s, sep);
  	while (start && s) {
    		s = next_token(s, sep);
    		start--;
  	}

  	if (!s || !*s)		/* ran off the end of the string */
    		return 0;

  	/* Find the end of the string that we want. */
  	r = s;
  	len--;
  	while (len && s) {
    		s = next_token(s, sep);
    		len--;
  	}

  	/* Chop off the end, and copy. No length checking needed. */
  	if (s && *s)
    		(void) split_token(&s, sep);
  	
  	strcpy(outstr, r);
  	return 1;
}	

int do_move_commod (dbref *zone, char *source, char *dest, int *qty) {
	return 1;
}

double parse_double (char *str)	{
	double td = 0;
	td = strtod(str, NULL);
	
	return td;
}

void crank (struct storage_t *sto, char *tn) {
	
	char ts[BUFFER_LEN];
	int i;
	
	snprintf(ts, sizeof(ts), "#%i|#%i|%i|%.3f|%s|%s|%.3f|%s|%.0f|%.3f|%.3f|",	
		sto->owner, 
		sto->oper,
		sto->upglevel, 
		sto->usedtons, 
		sto->destination, 
		sto->open,
		sto->prodrate, 
		sto->prodcommod, 
		sto->workers, 
		sto->wages, 
		sto->rent);
	//notify(6,ts);	
	if (sto->commods != 0) {
		strncat(ts, tprintf("%s-%.3f", sto->commod[0].name, sto->commod[0].qty), sizeof(ts) - 1);
	}
	
	if (sto->commods >= 1) {
		for (i=1; i < sto->commods; i++) {
			if (sto->commod[i].qty != 0) 
				strncat(ts, tprintf("~%s-%.3f",	sto->commod[i].name, sto->commod[i].qty), sizeof(ts) - 1);	
		}
	}	
	strcpy(tn, ts);
}

void uncrank (char *instr, struct storage_t *ts) {
	
	char item[BUFFER_LEN];
	char *ip;	
	char *storstr;
	double qty;
	int i, z;
	int x;
	
	
	ip = item;
	storstr = instr;
	ts->owner = parse_dbref(strsep(&storstr, "|"));
	ts->oper	= parse_dbref(strsep(&storstr, "|"));
	ts->upglevel = parse_integer(strsep(&storstr, "|"));
	ts->usedtons = parse_double(strsep(&storstr, "|"));
	strncpy(ts->destination,	strsep(&storstr, "|"), sizeof(ts->destination) -	1);
	strncpy(ts->open, strsep(&storstr, "|"), sizeof(ts->open) - 1);
	ts->prodrate = parse_double(strsep(&storstr, "|"));
	strncpy(ts->prodcommod, strsep(&storstr, "|"), sizeof(ts->prodcommod) - 1);
	ts->workers = parse_double(strsep(&storstr, "|"));
	ts->wages = parse_double(strsep(&storstr, "|"));
	ts->rent	= parse_double(strsep(&storstr, "|"));

	x = 0;
		
	z = do_wordcount(storstr, '-');
	if (z != 0) {
		z--;
	}
	
	for (i = 0; i != z; i++) {
		if (strlen(storstr) == 0) break;
		strcpy(ip, strsep(&storstr, "-"));			
		if (ip != NULL) {
			if (strlen(storstr) == 0) break;
			qty = parse_double(strsep(&storstr, "~"));
			if (qty	> 0) {
				ts->commod[x].qty = qty;
				strncpy(ts->commod[x].name, ip, sizeof(ts->commod[x].name) - 1);
				x++;
			}			
		} else break;		
	}
	
	ts->commods = x;
		
	//free(item);
	    
	//return ts; 
	//return ts;
}

int counts(const char *ord, char srchstr) {
	int ant = 0;
	int i;
	for (i = 0; i < (int)strlen(ord); i++) {
		if (ord[i] == srchstr) ant++;
	}
	return ant;
}

int get_store_str (dbref zone, char *obj, char *str) {
	ATTR *a;
	int sobj;
	char stxt[BUFFER_LEN];
	char storage[BUFFER_LEN];
	static char result[BUFFER_LEN];
	char *sp = stxt;
	char *rp = result;

	sobj = 0;
	strcpy(result, obj);
	strcpy(result, upcasestr(result));	  
	switch (result[0]) {
		case 'F':
			sobj = factory_data;
			safe_str("FAC",	stxt, &sp);
			break;
		case 'W':
			sobj = ware_data; 
			safe_str("WAR",	stxt, &sp);			   
			break;			      
		case 'M':
			switch (result[1]) {
				case 'I':
					sobj = mine_data; 
					safe_str("MIN",	stxt, &sp);					   
					break;
				case 'A':
					sobj = market_data; 
					safe_str("MAR",	stxt, &sp);					   
					break;
			} break;
		default: return	0;
	}
	
	if (sobj == 0) {
		return 0;
	}
	
	snprintf(storage, sizeof(storage), "%s_%s", unparse_dbref(zone), result);	 
	a = atr_get(sobj, storage);
	strcpy(str, atr_value(a));
	
	return 1;
}

double get_total_space(char *obj, int upglevel) {
	double sobj;	
	static char result[BUFFER_LEN];
	
	sobj = 0;
	strcpy(result, obj);
	strcpy(result, upcasestr(result));	  
	switch (result[0]) {
		case 'F':
			sobj = factory_space;
			break;
		case 'W':
			sobj = ware_space;
			break;			      
		case 'M':
			switch (result[1]) {
				case 'I':
					sobj = mine_space;
					break;
				case 'A':
					sobj = market_space;
					break;
			} break;
		default: return	0;
	}
	
	if (sobj == 0) {
		return 0;
	}
	
	return (sobj * upglevel);	
}	

int set_store_str (dbref zone, char *obj, char *str) {
	
	ATTR *a;
	int sobj;
	char stxt[BUFFER_LEN];
	
	char storage[BUFFER_LEN];
	static char result[BUFFER_LEN];
	char *sp = stxt;
	char *rp;
	int i;

	sobj = 0;
	strcpy(result, obj);
	strcpy(result, upcasestr(result));	  
	switch (result[0]) {
		case 'F':
			sobj = factory_data;
			safe_str("FAC",	stxt, &sp);
			break;
		case 'W':
			sobj = ware_data; 
			safe_str("WAR",	stxt, &sp);			   
			break;			      
		case 'M':
			switch (result[1]) {
				case 'I':
					sobj = mine_data; 
					safe_str("MIN",	stxt, &sp);					   
					break;
				case 'A':
					sobj = market_data; 
					safe_str("MAR",	stxt, &sp);					   
					break;
			} break;
		default: return	0;
	}
	
	if (sobj == 0) {
		return 0;
	}
	
	snprintf(storage, sizeof(storage), "%s_%s", unparse_dbref(zone), result);		 
	rp = &str[0];	     
	i = atr_add(sobj, storage, str,	GOD, (AF_MDARK + AF_WIZARD + AF_NOPROG));		 
	return 1;
}

struct storage_t calc_tons (struct storage_t ts) {
	int i;
	ts.usedtons = 0;
	for (i=0; i < ts.commods; i++) {
		if (ts.commod[i].name != NULL) {  
			ts.usedtons += ts.commod[i].qty;
		}
	}
	return ts;
}

int rem_zeros(struct storage_t *clist) {
	struct commod_t templist[MAX_STORAGE];
	
	int x,i;
	
	i = 0;
	
	for (x=0; x < MAX_STORAGE; x++) {
		strncpy(templist[x].name, "", sizeof(templist[x].name) - 1);
		templist[x].qty = 0;
	}
	
	for (x=0; x < clist->commods; x++) {
		if (clist->commod[x].qty != 0) {
			templist[i].qty = clist->commod[x].qty;
			strcpy(templist[i].name, clist->commod[x].name);
			i++;
		}
	}
	clist->commods = 0;
	for (x=0; x < i; x++) {
		if (templist[x].qty != 0) {
			clist->commod[x].qty = templist[x].qty;
			strcpy(clist->commod[x].name, templist[x].name);
			clist->commods++;
		}
	}
	
	return 1;	
}	

void has_commod(dbref zone, char *dest, char *commod, char *qty) {
	char tmp[BUFFER_LEN];
	char *tp = tmp;
	int found;
	struct storage_t *storages;  
	int i, err;
	double td;	  	
  
	found =	0;
	err = 1;		
	td = 0;
  
	storages = (struct storage_t *)malloc(sizeof(struct storage_t));

	if (get_store_str(zone,	dest, tmp) != 1) return;    
	uncrank(tmp, storages);
			
	for (i=0; i < storages->commods; i++) {
		if (storages->commod[i].name !=	NULL) {			       
			if (strcasecmp(storages->commod[i].name, commod) == 0) {				
				strcpy(qty, tprintf("%f",storages->commod[i].qty));								
			} else {
				strcpy(qty, "0");
			}
		}
	}
	
	free(storages);		
}

int do_add_commod (dbref zone, char *dest, char	*commod, char *qty) {
	char tmp[BUFFER_LEN];
	char *tp = tmp;
	int found;
	struct storage_t *storages;  
	int i, err;	
  
	found =	0;
	err = 1;
  
	storages = (struct storage_t *)malloc(sizeof(struct storage_t));

	if (get_store_str(zone,	dest, tmp) != 1) return	0;
    
	uncrank(tmp, storages);
		
	for (i=0; i < storages->commods; i++) {
		if (storages->commod[i].name !=	NULL) {			       
			if (strcasecmp(storages->commod[i].name, commod) == 0) {
				if ((storages->usedtons + parse_double(qty)) < get_total_space(dest, storages->upglevel)) {
					storages->commod[i].qty	+= parse_double(qty);
					found =	1;
				} else err = 2;
			}
		}
	}
	
	if (found == 0)	{
		if ((storages->usedtons + parse_double(qty)) < get_total_space(dest, storages->upglevel)) {
			i = storages->commods;
			strncpy(storages->commod[i].name, commod, sizeof(storages->commod[i].name) - 1);
			storages->commod[storages->commods].qty	= parse_double(qty);
			storages->commods++;
			found =	1;
		} else err = 2;		
	}
		
	i = rem_zeros(storages);	
	
	*storages = calc_tons(*storages);
	
	crank(storages, tp);
	i = set_store_str(zone,	dest, tp);
	
	free(storages);	
			
	return err;
}
		      
int do_rem_commod (dbref zone, char *dest, char	*commod, char *qty) {
	char tmp[BUFFER_LEN];
	char *tp = tmp;
	int found;
	struct storage_t *storages;  
	int i;	
  
	found =	0;
  
	storages = (struct storage_t *)malloc(sizeof(struct storage_t));

	if (get_store_str(zone,	dest, tmp) != 1) return	0;
    
	uncrank(tmp, storages);

	for (i=0; i < storages->commods; i++) {
		if (storages->commod[i].name !=	NULL) {			       
			if (strcasecmp(storages->commod[i].name, commod) == 0) {
				if (storages->commod[i].qty < parse_double(qty)) {
					return 0;
				} else {
					storages->commod[i].qty	-= parse_double(qty);
					found =	1;
				}
			}
		}
	}
		
	if (found == 0)	return 0;

	i = rem_zeros(storages);

	*storages = calc_tons(*storages);
	
	crank(storages, tp);
	i = set_store_str(zone,	dest, tp);
	
	free(storages);
			
	return 1;
}
		       
int validate_commod(char *commod) {
	ATTR *a;
	char *tmp;
	int found;
	
	found = 0;
	
	tmp = (char *)malloc(sizeof(tmp) * BUFFER_LEN + 1);
	
	a = atr_get(commod_data, "COMMODS");
	tmp = atr_value(a);
	
	do {
		if (strcasecmp(strsep(&tmp,"|"), commod) == 0) {		
			found = 1;			
		}
	} while (tmp != NULL);
	free(tmp);
	return found;	
}	

int return_commod(dbref enactor, char *commod, char *retstr) {
	ATTR *a;
	char commd[BUFFER_LEN];
	
	char *cp;
	
	char *tmp;
	char *tp;
	int found;
	
	found = 0;
	if (validate_commod(commod) == 1) {
		tmp = (char *)malloc(sizeof(char) * (BUFFER_LEN + 1));
	
		a = atr_get(commod_data, "COMMODS");
		strcpy(tmp, atr_value(a));
		tp = tmp;
		do {		
			cp = strsep(&tp,"|");
			if (strlen(cp) > 0) {
				if (strcasecmp(cp, commod) == 0) {
					found = 1;
					break;
				}
			}
		} while (strlen(tp) > 0);
		if (found == 1) strcpy(retstr,cp);
	
		free(tmp);
	}
		
	return found;
}

double get_morale(dbref zone) {
	ATTR *a;
	
	a = atr_get(zone, MORALE_ATTR);
	
	return parse_double(atr_value(a));
}

int get_commod(char *commod, struct commods_t *clist) {
	ATTR *a;
	char attrib[BUFFER_LEN];
	const char *ap;
	char values[BUFFER_LEN];
	char *vp;
	char *item;
	double qty;
	int i;
	int x;
	
	vp = &values[0];
	ap = &attrib[0];
	snprintf(attrib, sizeof(attrib), "%s_INFO", commod);
	strcpy(attrib, upcasestr(attrib));
	
	a = atr_get(commod_data, ap);
	if (a == NULL) {
		return 0;		
	}
	strncpy(vp, atr_value(a), sizeof(values) - 1);
	clist->cost = parse_double(strsep(&vp, "|"));
	clist->tech = parse_integer(strsep(&vp, "|"));
	clist->prodrate = parse_double(strsep(&vp, "|"));
	strncpy(clist->prodbld, strsep(&vp, "|"), sizeof(clist->prodbld) - 1);

	x = 0;
		
	if (strcasecmp(vp, "none") != 0)
		if (strlen(vp) > 0) {
			for (i = 0; i <	MAX_STORAGE; i++) {
				item = strsep(&vp, "-");
				if (item != NULL) {
					qty = parse_double(strsep(&vp, "~"));
					if (qty	> 0) {
						clist->req[x].qty = qty;
						strncpy(clist->req[x].name, item, sizeof(clist->req[x].name) - 1);
						x++;
					}
				}
			}
		}
		
	clist->reqs = x;
	
	return 1;
}


double get_agri_workers(dbref zone) {
	ATTR *a;
	double tmp;
	
	a = atr_get(zone, AGRI_WORKERS_ATTR);	
	if (a == NULL) {		
		return 0;
	}	
	tmp = parse_double(atr_value(a));
	return tmp;
}

void get_tax(dbref zone, char *tax) {
	ATTR *a;
		
	a = atr_get(zone, TAX_ATTR);	
	if (a == NULL) {		
		return;
	}	

	strcpy(tax, atr_value(a));
}

void add_taxes(dbref zone, double tax) {
	ATTR *a;
	double t;
		
	a = atr_get(zone, TAXES_ATTR);
	if (a == NULL) {		
		return;
	}	

	t = parse_double(atr_value(a));
	t += tax;
	
	(void) atr_add(zone, TAXES_ATTR,tprintf("%f", t) , GOD, AF_MDARK|AF_WIZARD|AF_NOPROG);
}

int get_food_source(dbref zone, char *source, char *dest) {
	ATTR *a;
	char temp[BUFFER_LEN];
	char *tp;
	
	tp = &temp[0];	
	a = atr_get(zone, FOOD_STORAGE_ATTR);
	if (a == NULL) {		
		return 0;
	}	
	
	strcpy(temp, atr_value(a));
		
	strcpy(source, strsep(&tp, "|"));
	strcpy(dest, strsep(&tp, "|"));
	
	return 1;
}

int uncrank_req(char *instr, char *commod, double qty) {	
	strcpy(commod, strsep(&instr, "-"));
	if (strlen(commod) == 0) return 0;
	qty = parse_double(strsep(&instr, " "));	
	return 1;	
}

double has_in_store (dbref zone, char *dest, char *commod) {
	char tmp[BUFFER_LEN];
	char *tp = tmp;
	int found;
	struct storage_t *storages;  
	int i, err;	
	double qty;
  
	found =	0;
	err = 1;
  
	storages = (struct storage_t *)malloc(sizeof(struct storage_t));

	if (get_store_str(zone,	dest, tmp) != 1) return	0;
    
	uncrank(tmp, storages);
	
	qty = 0;
		
	for (i=0; i < storages->commods; i++) {
		if (storages->commod[i].name !=	NULL) {			       
			if (strcasecmp(storages->commod[i].name, commod) == 0) {				
				qty = storages->commod[i].qty;
				found =	1;				
			}
		}
	}
	free(storages);
	return qty;
}

int uncrank_bank (dbref zone, char *struc, struct bank_t *bd) {
	ATTR *a;
	//struct bank_t bd;
	char item[BUFFER_LEN];
	char *ip;	
	char *storstr;
	double qty;
	int i, z;
	int x;
	
	a = atr_get(bank_data, tprintf("#%i_%s", zone, struc));
	if (a == NULL) {
		return 0;
	}
	
	storstr = (char *) alloca (sizeof(char) * (BUFFER_LEN + 1));
	strcpy(storstr, atr_value(a));
	
	bd->owner = parse_dbref(strsep(&storstr, "|"));
	bd->oper = parse_dbref(strsep(&storstr, "|"));
	bd->upglevel = parse_integer(strsep(&storstr, "|"));
	strcpy(bd->empty1, strsep(&storstr, "|"));
	bd->money = parse_double(strsep(&storstr, "|"));
	strcpy(bd->open, strsep(&storstr, "|"));
	strcpy(bd->empty2, strsep(&storstr, "|"));
	bd->interest = parse_double(strsep(&storstr, "|"));
	bd->workers = parse_double(strsep(&storstr, "|"));
	bd->wages = parse_double(strsep(&storstr, "|"));
	bd->rent = parse_double(strsep(&storstr, "|"));
	
	x = 0;
			
	z = do_wordcount(storstr, '~');
	if (z == 1) {
		z = 1;
	}
	
	for (i = 0; i != z; i++) {
		if (strlen(storstr) == 0) break;
		bd->account[x].holder = parse_dbref(strsep(&storstr, "-"));
		bd->account[x].has = parse_double(strsep(&storstr, "*"));
		bd->account[x].owe = parse_double(strsep(&storstr, "*"));
		bd->account[x].rent = parse_double(strsep(&storstr, "~"));
		x++;		
		if (storstr == NULL) break;
	}
	
	bd->accounts = x;
		
	//free(storstr);
	    
	//return ts; 
	return 1;
	
}

int crank_bank (dbref zone, char *struc, struct bank_t *bd) {
	ATTR *a;
	//struct bank_t bd;
	char item[BUFFER_LEN];
	char *ip;	
	char *storstr;
	double qty;
	int i, z;
	int x;
	
	snprintf(item, sizeof(item), "#%i|#%i|%i|%s|%f|%s|%s|%f|%f|%f|%f|",
		bd->owner,
		bd->oper,
		bd->upglevel,
		bd->empty1,
		bd->money,
		bd->open,
		bd->empty2,
		bd->interest,
		bd->workers,
		bd->wages,
		bd->rent);
	
	x = 0;
	
	if (bd->accounts > 0) {
		strcat(item, tprintf("#%i-%f*%f*%f",
			bd->account[x].holder,
			bd->account[x].has,
			bd->account[x].owe,
			bd->account[x].rent));
		x++;
	}
	
	if (bd->accounts > 1) 
		for (i=1; i != bd->accounts; i++) {
			strcat(item, tprintf("~#%i-%f*%f*%f",
				bd->account[x].holder,
				bd->account[x].has,
				bd->account[x].owe,
				bd->account[x].rent));
			x++;
		}
	
		
	x = atr_add(bank_data, tprintf("#%i_%s", zone, struc), item, GOD, AF_MDARK|AF_WIZARD|AF_NOPROG);
	
	return 1;
}	

void exch (char *from, char *qty) {
	int i,c,z;
	double texch,q;
	ATTR *a;
	char tmp[BUFFER_LEN];
	char ac[20];
	char *tp;
		
	q = parse_double(qty);		
	tp = (char *) alloca (BUFFER_LEN);
	
	a = atr_get(econ_data, CURRENCIES_ATTR);
	if (a == NULL) return;
	strcpy(tp, atr_value(a));
	i = 0;
	z = 0;
	texch = 0;
	for (i = 0; i != (do_wordcount(tp, ' ') + 1); i++) {
		strncpy(ac, strsep(&tp, " "), 19);
		if (strcasecmp(from, ac) == 0) break;
		z++;
	}
	
	a = atr_get(econ_data, EXCH_RATE_ATTR);
	if (a == NULL) return;
	strcpy(tp, atr_value(a));
	for (c = 0; c < (z + 1); c++) {
		texch = parse_double(strsep(&tp, " "));
	}
	
	strcpy(qty,tprintf("%f",(q * texch)));
	
}

int deposit_account (dbref zone, char *building, char *account, double amount) {
	
	struct bank_t *bankdata;
	int found, i;
	
	found = 0;
	bankdata = (struct bank_t *) alloca (sizeof(struct bank_t));
	
	if (uncrank_bank(zone, building, bankdata) == 0) {
		return 0;
	}
	
	for (i=0; i < bankdata->accounts; i++) {
		if (bankdata->account[i].holder == parse_dbref(account)) {
			bankdata->account[i].has += amount;
			found = 1;
		}
	}
	
	if (crank_bank(zone, building, bankdata) == 0) {
		return 0;
	}
	
	if (found == 0) {
		return 0;
	}
	
	return 1;
}
			
int withdraw_account (dbref zone, char *building, char *account, double amount) {
	
	struct bank_t *bankdata;
	int found, i;
	
	found = 0;
	bankdata = (struct bank_t *) alloca (sizeof(struct bank_t));
	
	if (uncrank_bank(zone, building, bankdata) == 0) {
		return 0;
	}
	
	for (i=0; i < bankdata->accounts; i++) {
		if (bankdata->account[i].holder == parse_dbref(account)) {
			if ((amount < bankdata->account[i].has) || (amount == bankdata->account[i].has)) {
				bankdata->account[i].has -= amount;
				found = 1;
			} else found = -1;
		}
	}
	
	if (crank_bank(zone, building, bankdata) == 0) {
		return 0;
	}
	
	if (found == 0) {
		return 0;
	}
	if (found == -1) {
		return -1;
	}
	return 1;
}

int check_account (dbref zone, char *building, char *account, char *amount) {
	
	struct bank_t *bankdata;
	int found, i;
	
	found = 0;
	bankdata = (struct bank_t *) alloca (sizeof(struct bank_t));
	
	if (uncrank_bank(zone, building, bankdata) == 0) {
		return 0;
	}
	
	for (i=0; i < bankdata->accounts; i++) {
		if (bankdata->account[i].holder == parse_dbref(account)) {			
			strcpy(amount, tprintf("%f",bankdata->account[i].has));
			found = 1;			
		}
	}
	
	if (crank_bank(zone, building, bankdata) == 0) {
		return 0;
	}
	
	if (found == 0) {
		return 0;
	}	
	return 1;
}

void do_reposess (dbref zone, char *dest) {
	char tmp[BUFFER_LEN];
	char *tp = tmp;
	struct storage_t *storages;  
	  
	storages = (struct storage_t *) alloca (sizeof(struct storage_t));

	if (get_store_str(zone,	dest, tmp) != 1) return;
    
	uncrank(tmp, storages);
	
	storages->oper = storages->owner;
	strcpy(storages->open, T("Closed"));	
	
	crank(storages, tp);
	(void) set_store_str(zone, dest, tp);		
	
}
